﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;

namespace SMplusXTeam.SyncMoped.SyncGurke
{
    /// <summary>
    /// Compares two directories.
    /// </summary>
    public static class DirectoryComparison
    {
        public static event ProgressHandler CompareProgess;

        static DirectoryComparison()
        {
            CompareProgess += (o, e) => { };
        }

        private static void ReportProgress(Object sender, ProgressStatusArgs e)
        {
            decimal currentFileNr = e.CurrentFileNr;
            decimal allFilesCount = e.TotalFileCount;
            TraceSource traceSource = new TraceSource(sender.ToString());
            traceSource.TraceEvent(TraceEventType.Information, 1, Math.Round((decimal)100 * (currentFileNr) / (allFilesCount), 2) + "%");
            traceSource.Close();
        }

        /// <summary>
        /// Compares two directories and determines the comparison result.
        /// </summary>
        /// <param name="allSourceFiles">The files of the source directory.</param>
        /// <param name="targetDirectory">The target directory.</param>
        /// <param name="comparisonMethod">The <see cref="ComparisonMethod">comparion method</see>.</param>
        /// <returns><see cref="ComparisonMethod"/><para>The result of the comparison.</para></returns>
        public static DirectoryComparisonResult CompareDirectories(String sourceDirectory, String targetDirectory, ComparisonMethod comparisonMethod)
        {
            CompareProgess += ReportProgress;
            DirectoryComparisonResult result = new DirectoryComparisonResult();
            var allTargetFiles = from f in FileHelper.GetFiles(targetDirectory)
                                 select FileHelper.GetRelativePath(f, targetDirectory);
            var allSourceFiles = from f in FileHelper.GetFiles(sourceDirectory)
                                 select FileHelper.GetRelativePath(f, sourceDirectory);
            var deletedFiles = new List<String>(allTargetFiles);

            long counter = 0;
            long total = allSourceFiles.LongCount();

            foreach (String sourceFile in allSourceFiles)
            {
                counter++;
                DirectoryComparison.CompareProgess(sourceDirectory, new ProgressStatusArgs(counter, total));                

                String foundtargetFile = allTargetFiles.FirstOrDefault(t => (t == sourceFile));
                try
                {
                    if (String.IsNullOrEmpty(foundtargetFile))
                    {
                        deletedFiles.Remove(sourceFile);
                        result.NewFiles.Add(sourceFile);
                    }
                    else
                    {
                        deletedFiles.Remove(sourceFile);
                        if (FileHelper.IsFileBackedUp(
                                Path.Combine(sourceDirectory, sourceFile), 
                                Path.Combine(targetDirectory, foundtargetFile), 
                                comparisonMethod
                            ))
                        {
                            result.EqualFiles.Add(Path.Combine(sourceDirectory, sourceFile));
                        }
                        else
                        {
                            result.UnequalFiles.Add(Path.Combine(sourceDirectory, sourceFile));
                        }
                    }
                }
                catch (Exception ex)
                {
                    result.FailedFiles.Add(sourceFile, ex);
                    TraceSource traceSource = new TraceSource(typeof(DirectoryComparison).ToString());
                    traceSource.TraceEvent(TraceEventType.Warning, 1, ex.Message);
                    traceSource.Close();
                }
            }
            result.DeletedFiles.AddRange(from f in deletedFiles
                                         select Path.Combine(sourceDirectory, f));
            return result;
        }

        public delegate void ProgressHandler(Object sender, ProgressStatusArgs e);

        /// <summary>
        /// Defines the arguments of the sync-progress.
        /// </summary>
        public class ProgressStatusArgs : EventArgs
        {
            /// <summary>
            /// The current nr of the file.
            /// </summary>
            public long CurrentFileNr { get; private set; }

            /// <summary>
            /// Total nr of files.
            /// </summary>
            public long TotalFileCount { get; private set; }

            /// <summary>
            /// Initializes the progress arguments.
            /// </summary>
            /// <param name="fileNr"></param>
            /// <param name="totalFiles"></param>
            public ProgressStatusArgs(long fileNr, long total)
            {
                this.CurrentFileNr = fileNr;
                this.TotalFileCount = total;
            }
        }

    }
}
